package org.liveboardgames.agricola.model
{
	import com.adobe.cairngorm.control.CairngormEventDispatcher;
	
	import mx.collections.ArrayCollection;
	import mx.collections.ListCollectionView;
	
	import org.liveboardgames.agricola.control.delegates.action.AgricolaActionController;
	import org.liveboardgames.agricola.control.delegates.helper.GameHelper;
	import org.liveboardgames.agricola.control.events.StartHarvestEvent;
	import org.liveboardgames.agricola.vo.Game;
	import org.liveboardgames.agricola.vo.board.BoardTile;
	import org.liveboardgames.agricola.vo.card.ActionCard;
	import org.liveboardgames.agricola.vo.card.Card;
	import org.liveboardgames.agricola.vo.common.Peep;
	import org.liveboardgames.agricola.vo.farm.Farm;
	import org.liveboardgames.agricola.vo.farm.FarmTile;
	import org.liveboardgames.agricola.vo.player.Player;
	import org.liveboardgames.agricola.vo.player.Score;
	import org.liveboardgames.common.dictionary.collections.HashCollection;
	import org.liveboardgames.common.dictionary.collections.IMap;

	public class ModelUpdater
	{
		private var locator:AgricolaModelLocator;

		public function ModelUpdater(modelLocator:AgricolaModelLocator)
		{
			this.locator = modelLocator;
		}

		public function updateModel(change:Object):void
		{
			var type:String = change.type;
			var object:Object = change.object;

			if (type == null)
			{
				throw new Error("Unsupported change: " + type);
			}

			if (type == "GAME")
			{
				locator.game = object as Game;
				locator.actionController = new AgricolaActionController(locator.game);
			}
			else if (type == "CARD")
			{
				updateCard(object as Card);
			}
			else if (type == "FARM_TILE")
			{
				updateFarmTile(object as FarmTile);
			}
			else if (type == "PEEP")
			{
				updatePeep(object as Peep);
			}
			else if (type == "WAITING_ACTIONS")
			{
				locator.game.waitingActionCards = object as ListCollectionView;
			}
			else if (type == "BOARD_TILE")
			{
				updateBoardTile(object as BoardTile);
			}
			else if (type.lastIndexOf("FARM_RESOURCES") != -1)
			{
				var underscoreIndex:int = type.lastIndexOf("_");
				var farmId:int = int(type.substring(underscoreIndex + 1));
				updateFarmResources(object as HashCollection, farmId);
			}
			else if (type == "CURRENT_PLAYER")
			{
				updateCurrentPlayer(object as int);
			}
			else if (type == "PLAYER_PLAYED_PEEP")
			{
				locator.game.hasPlayerPlayedPeep = object as Boolean;
			}
			else if (type == "PLAYER_ORDER")
			{
				updatePlayerOrder(object as ListCollectionView);
			}
			else if (type == "AVAILABLE_FENCES")
			{
				locator.popups.numberOfAvailableFences = int(object);
			}
			else if (type.lastIndexOf("REMOVE_PLAYED_CARDS") != -1)
			{
				var underscoreIndex:int = type.lastIndexOf("_");
				var farmId:int = int(type.substring(underscoreIndex + 1));
				removePlayedCard(object as int, farmId);
			}
			else if (type.lastIndexOf("ADD_PLAYED_CARDS") != -1)
			{
				var underscoreIndex:int = type.lastIndexOf("_");
				var farmId:int = int(type.substring(underscoreIndex + 1));
				addPlayedCard(object as Card, farmId);
			}
			else if (type == "ADD_MAJOR_IMPROVEMENT")
			{
				locator.game.majorImprovements.addItem(object);
			}
			else if (type == "REMOVE_MAJOR_IMPROVEMENT")
			{
				locator.game.removeMajorImprovementById(object as int);
			}
			else if (type.lastIndexOf("PLAYER_NEW_PEEP") != -1)
			{
				var underscoreIndex:int = type.lastIndexOf("_");
				var playerId:int = int(type.substring(underscoreIndex + 1));
				addPeepForPlayer(object as Peep, playerId);
			}
			else if (type == "HARVEST_START")
			{
				var startHarvestEvent:StartHarvestEvent = new StartHarvestEvent(StartHarvestEvent.START_HARVEST);
            	startHarvestEvent.game = locator.game;
                CairngormEventDispatcher.getInstance().dispatchEvent(startHarvestEvent);
			}
			else if (type == "RESET_HARVEST")
			{
				locator.harvestController.isFinished = true;
				locator.game.harvestFieldPlayers = new HashCollection();
				locator.game.harvestFeedPlayers = new HashCollection();
				locator.game.harvestBreedPlayers = new HashCollection();
			}
			else if (type == "HARVEST_FEED_NEW")
			{
				var player:Player = GameHelper.getPlayerById(locator.game, object as int);
				locator.game.harvestFeedPlayers.addItem(player);
			}
			else if (type == "HARVEST_FIELD_NEW")
			{
				var player:Player = GameHelper.getPlayerById(locator.game, object as int);
				locator.game.harvestFieldPlayers.addItem(player);
			}
			else if (type == "HARVEST_BREED_NEW")
			{
				var player:Player = GameHelper.getPlayerById(locator.game, object as int);
				locator.game.harvestBreedPlayers.addItem(player);
			}
			else if (type == "GAME_FINISHED")
			{
				locator.game.isFinished = true;
			}
			else if (type.lastIndexOf("PLAYER_SCORE") != -1)
			{
				var underscoreIndex:int = type.lastIndexOf("_");
				var playerId:int = int(type.substring(underscoreIndex + 1));
				updatePlayerScore(playerId, object as Score);
			}
			else
			{
				throw new Error("Unsupported change: " + type);
			}
		}
		
		private function updatePlayerScore(playerId:int, score:Score):void
		{
			var player:Player = GameHelper.getPlayerById(locator.game, playerId);
			player.score = score;
		}
		

		private function removePlayedCard(cardId:int, farmId:int):void
		{
			for each (var player:Player in locator.game.players)
			{
				var farm:Farm = player.farm;
				if (farm.id == farmId)
				{
					// Now remove the card
					farm.removePlayedCardById(cardId);
					break;
				}
			}
		}

		private function addPlayedCard(card:Card, farmId:int):void
		{
			for each (var player:Player in locator.game.players)
			{
				var farm:Farm = player.farm;
				if (farm.id == farmId)
				{
					// Now remove the card
					farm.addPlayedCard(card);
					break;
				}
			}
		}

		private function updateCard(changedCard:Card):void
		{
			var cards:IMap = GameHelper.getAllPlayedCards(locator.game);

			for each (var card:Card in cards.getKeys())
			{
				if (card.cardId == changedCard.cardId)
				{
					var container:Object = cards.getValue(card);
					if (container is BoardTile)
					{
						// Only action cards can exist on the board
						BoardTile(container).actionCard = ActionCard(changedCard);
					}
					else if (container is ListCollectionView)
					{
						var list:ListCollectionView = container as ListCollectionView;
						var index:int = list.getItemIndex(card);
						list.setItemAt(changedCard, index);
					}
					else
					{
						throw new Error("Unsupported container: " + container);
					}
					break;
				}
			}
		}

		private function updateFarmTile(changedTile:FarmTile):void
		{
			for each (var player:Player in locator.game.players)
			{
				var tiles:ListCollectionView = player.farm.tiles;
				for each (var tile:FarmTile in tiles)
				{
					if (tile.uniqueId == changedTile.uniqueId)
					{
						var index:int = tiles.getItemIndex(tile);
						tiles.setItemAt(changedTile, index);
						break;
					}
				}
			}
		}

		private function updatePeep(changedPeep:Peep):void
		{
			var peeps:ListCollectionView = GameHelper.getAllPeeps(locator.game);

			for each (var peep:Peep in peeps)
			{
				if (peep.id == changedPeep.id)
				{
					peep = changedPeep;
				}
			}
		}

		private function updateBoardTile(changedTile:BoardTile):void
		{
			var tiles:ListCollectionView = locator.game.tiles;

			for each (var tile:BoardTile in tiles)
			{
				if (tile.uniqueId == changedTile.uniqueId)
				{
					var index:int = tiles.getItemIndex(tile);
					tiles.setItemAt(changedTile, index);
					break;
				}
			}
		}

		private function addPeepForPlayer(peep:Peep, playerId:int):void
		{
			var player:Player = GameHelper.getPlayerById(locator.game, playerId);
			player.peeps.addItem(peep);
		}

		private function updateFarmResources(changedResources:HashCollection, farmId:int):void
		{
			for each (var player:Player in locator.game.players)
			{
				var farm:Farm = player.farm;
				if (farm.id == farmId)
				{
					farm.resources = changedResources;
					break;
				}
			}
		}

		private function updateCurrentPlayer(playerId:int):void
		{
			for each (var player:Player in locator.game.players)
			{
				if (player.id == playerId)
				{
					locator.game.currentPlayer = player;
					break;
				}
			}
		}

		private function updatePlayerOrder(newOrder:ListCollectionView):void
		{
			var tempPlayers:ListCollectionView = new ArrayCollection();

			for each (var playerId:int in newOrder)
			{
				for each (var player:Player in locator.game.players)
				{
					if (player.id == playerId)
					{
						tempPlayers.addItem(player);
					}
				}
			}

			for (var i:int = 0; i < tempPlayers.length; i++)
			{
				locator.game.players.setItemAt(tempPlayers.getItemAt(i), i);
			}
		}
	}
}